package com.shark.shiro;

import java.util.concurrent.atomic.AtomicInteger;

import javax.servlet.http.HttpSession;

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;

import com.shark.commons.constants.BaseConst;
import com.shark.commons.spring.SpringContextHolder;

/**
 * 密码重试次数限制
 * 最大出错次数利用缓存实现，验证码次数用session实现
 * @author Administrator
 *
 */
public class ShiroRetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {

	private Cache<String, AtomicInteger> shiroPasswordRetryCache;
	private boolean validateCodeEbabled = true; 		// 是否开启验证码支持
	private int showValidateCodeRetryCount = 3; 		// 验证出错次数显示验证码
	private int maxRetryCount = 5; 						// 密码最大重试次数

	public void setValidateCodeEbabled(final boolean captchaEbabledParm) {
		this.validateCodeEbabled = captchaEbabledParm;
	}

	public void setShowValidateCodeRetryCount(final int showValidateCodeRetryCount) {
		this.showValidateCodeRetryCount = showValidateCodeRetryCount;
	}

	public ShiroRetryLimitHashedCredentialsMatcher(final CacheManager cacheManager) {
		shiroPasswordRetryCache = cacheManager.getCache("ShiroPasswordRetryCache");
	}

	public void setMaxRetryCount(final int maxRetryCountParm) {
		this.maxRetryCount = maxRetryCountParm;
	}

	@Override
	public boolean doCredentialsMatch(final AuthenticationToken token, final AuthenticationInfo info) {
		HttpSession session = SpringContextHolder.getHttpSession();
		String username = (String) token.getPrincipal();
		
		// 缓存里的错误次数
		AtomicInteger retryCount = shiroPasswordRetryCache.get(username);
		if (retryCount == null) {
			retryCount = new AtomicInteger(0);
			shiroPasswordRetryCache.put(username, retryCount);
		}
		int count = retryCount.incrementAndGet();
		if (count > maxRetryCount) { // 是否超过最大次数
			throw new LockedAccountException();
		}
		// session里的错误次数 ，用于显示验证码
		AtomicInteger sessionRetryCount = (AtomicInteger) session.getAttribute(BaseConst.SESSION_RETRY_COUNT);
		if (sessionRetryCount == null) {
			sessionRetryCount = new AtomicInteger(0);
			session.setAttribute(BaseConst.SESSION_RETRY_COUNT, sessionRetryCount);
		}
		int sessionRetryErrorCount = sessionRetryCount.incrementAndGet();

		boolean matches = super.doCredentialsMatch(token, info);
		if (matches) {
			shiroPasswordRetryCache.remove(username);
			session.setAttribute(BaseConst.SHOW_VALIDATE_CODE, false);
		} else if (validateCodeEbabled && sessionRetryErrorCount >= showValidateCodeRetryCount) { // 判断是否显示验证码
			session.setAttribute(BaseConst.SHOW_VALIDATE_CODE, true); // 需要输入验证码
			throw new ExcessiveAttemptsException();
		}
		return matches;
	}
}
